
#pragma once
#include "searuleset.h"
#include <fstream>
//#include <boost/thread.hpp>

/** This struct has enough information to compare two SEARuleSets. */
struct fitnessize
{
	int fitness;	//fitness
	int ruleNum;	//number of SEARules in the SEARuleset
	int infoSize;	//total informations in bits needed to store the SEARuleSet.
};

/** 
 * This class provides all the functionality to initiate and run a Symbiotic Evolutionary Algorithm.
 */
class SEA
{
public:
	int maxIteration;
	int populationSize;
	int selectedSize;		//!< Number of selected individuals to reproduce.
	int tournamentSize;
	int indSizeLimit;
	int eliteSize;
	int diversitySize;		//!< Number of random individuals added to the pool in each itteration.
	string outputFolder;
	ofstream logFile;
	int nBRadius;			//!< The radius in which the individuals can look for the answer
	int historySize;		//!< How many steps in the past the individuals can look in.
	int highestFitnessSoFar;
	vector<SEARuleSet> individuals;
	vector<int> selectedIndices;
	vector<int> eliteIndices;
	vector<fitnessize> indFitnessize;	
	
	void updateFitnessizes();	

	EightLayerIM picToBuild;	//TODO: should be set in either constructor or another function.
	int firstLayer;
	int lastLayer;

	void initiatePool();
	void updateSizeLimit();
	void chooseSelected ();
	void mutateSelectedAddToPool();
	int xOverSelectedAddToPool();	//!< Returns the number of children it added to the pool (child is only added if it is fitter than both parents).
	void diversify();
	void killExtras();
	bool isFitter (int i, int j) const;	//!< This helper function tells if individuals[i] has a higher fitness, or equal fitness and smaller size than individuals[j].
	bool equalyFit (int i, int j) const;
	bool isElite (int i) const;			//!< Returns true if i is an emelent in eliteIndices.
	void updateBestIndividuals();
	bool checkDataMembersAreSet () const;
	void printFitnesses (ofstream& file) const;
	void printRuleNums (ofstream& file) const;
	void printInfoSizes (ofstream& file) const;
	void printSelecteds (ofstream& file) const;
	void printElites (ofstream& file) const;

	//SEA(int nbradius, int historysteps, int popSize, int selectedSize, int tournamentSize, int indSizeLimit, int eliteSize, int diversitySize, string logFileName = "SEALog.txt");
	SEA(const EightLayerIM& elim);
	SEA(const SEA& other);
	void setMaxIteration (int mi) {maxIteration = mi;}
	void setPopulationSize (int ps) {populationSize = ps;}
	void setSelectedSize (int ss) {selectedSize = ss;}
	void setTournamentSize (int ts) {tournamentSize = ts;}
	void setIndSizeLimit (int is) {indSizeLimit = is;}
	void setEliteSize (int es) {eliteSize = es;}
	void setDiversitySize (int ds) {diversitySize = ds;}
	void setNBRadius (int nr ) {nBRadius = nr;}
	void setHitorySize (int hs) {historySize = hs;}
	void setFirstLayer (int fl) {firstLayer = fl;}
	void setLastLayer (int ll) {lastLayer = ll;}
	void setLoggerFile (string fileName);
	void setOutputFolder (string folderName);

	void run (bool onlineReport = true);
#ifdef VC110
	void updateFitnessInBlock(int firstIndIndex, int lastIndIndex, EightLayerIM& picCopy);//!< Updates the indFitnessizes for the individuals whose indices are given.
	void updateFitnessizes_MultiThread();
#endif
	//friend void freeUpdateFitnessInBlock (vector<SEARuleSet>& inds, vector<fitnessize>& fitnessizes, int firstIndex, int lastIndex, EightLayerIM picCopy, int firstLayer, int lastLayer);
};